import { assetManager, Canvas, Component, Constructor, instantiate, js, Layers, Node, Prefab, ResolutionPolicy, screen, Size, UITransform, view } from 'cc';
import { ResLoader } from '../res/ResLoader';
import { EViewLayer } from './EViewLayer';

/** 预制体信息<uiClassName: IBundleUrl> */
const uiNameBUrlMap = new Map<string, IBundleUrl>();
/**
 * 注册预制体信息 
 * @param cfg {[uiClassName: string]: IBundleUrl} 预制体配置数据
 */
export function registerUINameBUrlByCfg(cfg: {[uiClassName: string]: IBundleUrl}) {
    for (let uiClassName in cfg) {
        uiNameBUrlMap.set(uiClassName, cfg[uiClassName])
    }
}

/** 预制体信息<uiClass: IBundleUrl> */
const uiClassBUrlMap = new Map<any, IBundleUrl>();
/** 添加uiClass-预制体信息 */
export function setUIClassBUrl(uiClass: any, bUrl: IBundleUrl) {
    uiClassBUrlMap.set(uiClass, bUrl)
}
/** 获取预制体信息通过uiClass */
export function getUIClassBUrl(uiClass: any): IBundleUrl {
    // 如果存在uiClass-IBundleUrl数据
    if (uiClassBUrlMap.has(uiClass)) {
        return uiClassBUrlMap.get(uiClass);
    }
    // 如果没有，先从配置中获取，再添加
    let uiClassName = js.getClassName(uiClass);
    let bUrl = uiNameBUrlMap.get(uiClassName);
    if (!bUrl) {
        // 没有找到类名对应的预制体
        debugger;
        console.error("没有找到类名对应的预制体 uiClassName: ", uiClassName);
        return null;
    }
    // 添加uiClass-预制体信息
    setUIClassBUrl(uiClass, bUrl);
    return bUrl;
}

/** 画布的标准化尺寸 */
export const G_VIEW_SIZE = new Size(0, 0);
/** 适配屏幕 */
function adapterScreen() {
    let resolutionPolicy: ResolutionPolicy = view.getResolutionPolicy();
    let designSize = view.getDesignResolutionSize();
    let frameSize = screen.windowSize;
    let frameW = frameSize.width;
    let frameH = frameSize.height;
    /** 是否是屏幕更宽 */
    const isScreenWidthLarger = (frameW / frameH) > (designSize.width / designSize.height);
    let targetResolutionPolicy = isScreenWidthLarger ? ResolutionPolicy.FIXED_HEIGHT : ResolutionPolicy.FIXED_WIDTH;
    if (targetResolutionPolicy !== resolutionPolicy.getContentStrategy().strategy) {
        /** 保证设计分辨率的内容都能显示出来 */
        view.setDesignResolutionSize(designSize.width, designSize.height, targetResolutionPolicy);
        view.emit("canvas-resize")
    }

    /** 实际的尺寸会和设计分辨率在一个维度，但是宽或高更大 */
    if (isScreenWidthLarger) {
        G_VIEW_SIZE.width = Math.ceil(designSize.height * frameSize.width / frameSize.height);
        G_VIEW_SIZE.height = designSize.height;
    } else {
        G_VIEW_SIZE.width = designSize.width;
        G_VIEW_SIZE.height = Math.ceil(designSize.width * frameSize.height / frameSize.width);
    }

    console.log(`屏幕${isScreenWidthLarger ? "更宽, 高度适配" : "更高, 宽度适配"} 设计分辨率比例下的屏幕尺寸: ${G_VIEW_SIZE.width}x${G_VIEW_SIZE.height}`);

    return isScreenWidthLarger;
}

class MyLayer {
    public readonly node: Node;
    constructor(
        public readonly layer: EViewLayer,
        public readonly canvas: Canvas,
        name: string,
    ) {
        const node = this.node = new Node(name);
        node.layer = Layers.Enum.UI_2D;
        node.addComponent(UITransform);
        canvas.node.addChild(node);
    }
}

export class UIManager {
    public canvas: Canvas = null;
    public playerCanvas: Canvas = null;
    private myLayers: MyLayer[] = []

    /** 初始化所有基础UI层 */
    init(canvas: Canvas, playerCanvas: Canvas) {
        this.canvas = canvas;
        this.playerCanvas = playerCanvas;
        // 屏幕适配
        adapterScreen();
        // 创建所有UI层
        for (let layer = EViewLayer.Scene, maxLayer = EViewLayer.Toast; layer <= maxLayer; ++layer) {
            this.myLayers.push(new MyLayer(layer, canvas, EViewLayer[layer]));
        }
    }

    /**
     * 打开UI
     * @param uiClass UI类
     * @returns Promise<UI> 返回打开的UI
     */
    async open<UI extends Component>(uiClass: Constructor<UI> & { readonly viewLayer?: EViewLayer; }): Promise<UI> {
        const viewLayer: EViewLayer = typeof (uiClass.viewLayer) === 'number' ? uiClass.viewLayer : EViewLayer.UI
        const resLoader = new ResLoader();
        resLoader.addUI(uiClass);
        await resLoader.load();
        let ui = this.instantiate(uiClass);
        this.myLayers[viewLayer].node.addChild(ui.node);
        ui.getComponent(UITransform).setContentSize(G_VIEW_SIZE.clone());
        resLoader.addAutoRelease(ui);
        return ui;
    }

    /**
     * 实例化UI
     * @param ueClass UI类
     * @returns UI
     */
    instantiate<UE extends Component>(ueClass: Constructor<UE>): UE {
        let bUrl = getUIClassBUrl(ueClass);
        let bundle = assetManager.getBundle(bUrl.bundleName);
        let prefab: Prefab = bundle.get(bUrl.assetName, Prefab);
        let node: Node = instantiate(prefab);
        return (node.getComponent(ueClass as any) || node.addComponent(ueClass as any)) as any as UE;
    }
}